import { ready, getApiPath, assert } from '@/lib/utils';
import { get, postJson } from '@/lib/request';
import * as v from 'valibot';
import { File } from '@/types/file';
import { getFileIcon } from '@/lib/file-icon';
import { handleFileAction } from '@/lib/file';
import Sortable from 'sortablejs';
import { getCurrentUserPerm } from '@/api/user';
import { filesize } from "filesize";
import { formatDateZhCn } from '@/lib/utils';
import { FileUploader } from '@/components/file-uploader';
import * as FilePond from 'filepond';

interface FileNode {
    type: 'file';
    name: string;
    file: File;
}

interface DirectoryNode {
    type: 'directory';
    name: string;
    children: Record<string, FileNode | DirectoryNode>;
}

type exportFileType = 'upload' | 'existing';

interface exportFile {
    id: string,
    type: exportFileType,
    path: string
}

let canManage: boolean = false;
let hasChanged: boolean = false;

const classNames = {
    folder: 'folder tw:rounded-md',
    folderHeader: 'folder-header tw:flex tw:items-center tw:cursor-pointer tw:hover:bg-gray-100 tw:py-1 tw:px-2 tw:rounded-md tw:group',
    file: 'file tw:flex tw:items-center tw:gap-2 tw:hover:bg-gray-100 tw:py-1 tw:px-2 tw:rounded-md tw:group',
    fileUploader: 'file-uploader tw:ml-1',
}


function setHasChanged(changed: boolean = true) {
    const saveBtn = document.getElementById('save-changes-btn');
    if (changed) {
        hasChanged = true;
        if (saveBtn) saveBtn.classList.add('tw:btn-warning', 'tw:animate-pulse');
        
    } else {
        hasChanged = false;
        if (saveBtn) saveBtn.classList.remove('tw:btn-warning', 'tw:animate-pulse');
    }
}

/**
 * Groups files into a hierarchical structure suitable for a file explorer
 */
function groupFiles(files: File[]) {
    const root: DirectoryNode = {
        type: 'directory',
        name: '/',
        children: {},
    };

    for (const file of files) {
        let directoryPath = file.relation_name === '' ? '/' : file.relation_name;
    
        if (!directoryPath.startsWith('/')) {
            directoryPath = '/' + directoryPath;
        }
    
        const segments = directoryPath.split('/').filter(segment => segment !== '');
    
        let currentDirectory = root;
    
        for (const segment of segments) {
            if (!currentDirectory.children[segment] || currentDirectory.children[segment].type !== 'directory') {
                currentDirectory.children[segment] = {
                    type: 'directory',
                    name: segment,
                    children: {},
                };
            }
      
            currentDirectory = currentDirectory.children[segment] as DirectoryNode;
        }
    
        // handle files with same file name and path
        let key = file.filename;
        if (key in currentDirectory.children) key = `${key}-0`;
        while (key in currentDirectory.children) {
            const parts = key.split("-");
            const fileName = parts.join("-");
            const index = Number(parts.pop());
            key = `${fileName}-${index + 1}`;
        }
        currentDirectory.children[key] = {
            type: 'file',
            name: file.filename,
            file: file,
        };
    }

    return root;
}

function setupFileExplorer(files: File[]) {
    const fileExplorerElem = document.getElementById("file-explorer") as HTMLDivElement;
    assert(fileExplorerElem, "Cannot find element with id `file-explorer`!");

    const structuredFiles = groupFiles(files);
    fileExplorerElem.innerHTML = '';
    
    addTopLevelFolderControl(fileExplorerElem);
    
    // Add top level controls if user can manage files
    if (canManage) {
        // Add event listener for top-level buttons
        document.getElementById('toplevel-add-category-btn')?.addEventListener('click', () => {
            createFolder(fileExplorerElem);
        });
        document.getElementById("toplevel-add-file-btn")?.addEventListener("click", () => {
            createFileUploader(fileExplorerElem);
        });
        
        document.getElementById('save-changes-btn')?.addEventListener('click', async () => {
            let json;
            try {
                json = await exportJSON();
            } catch (e: any) {
                alert(e.message);
                return;
            }
            
            if (!hasChanged) {
                alert(gettext("没有修改，无需保存。"));
                return;
            }

            await postJson(String(window.location), json);

            setHasChanged(false);

            location.reload();
        });
    }
    
    renderDirectoryContents(structuredFiles, fileExplorerElem);
    setupEventListeners();
}


function addTopLevelFolderControl(fileExplorerElem: HTMLElement) {
    const controlsDiv = document.createElement('div');
    controlsDiv.className = 'tw:flex tw:justify-between tw:items-center tw:mb-4 tw:pb-2 tw:border-b tw:border-gray-200';
    
    controlsDiv.innerHTML = `
<h2 class="tw:text-lg tw:font-semibold">${gettext("文件")}</h2>
<div class="tw:flex tw:gap-2 tw:items-center">
    ${!canManage ? '' : `
    <button id="toplevel-add-category-btn" class="by6-crumbs-action-btn tw:h-8 tw:text-sm">
      <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="tw:size-5">
        <path stroke-linecap="round" stroke-linejoin="round" d="M12 10.5v6m3-3H9m4.06-7.19-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" />
      </svg>
      ${gettext("添加根文件夹")}
    </button>

    <button id="toplevel-add-file-btn" class="by6-crumbs-action-btn tw:h-8 tw:text-sm">
      <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="tw:size-5">
        <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m3.75 9v6m3-3H9m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" />
      </svg>
      ${gettext("上传文件")}
    </button>

    <button id="save-changes-btn" class="by6-crumbs-action-btn tw:h-8 tw:text-sm">
      <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="tw:size-5">
        <path stroke-linecap="round" stroke-linejoin="round" d="M9 3.75H6.912a2.25 2.25 0 0 0-2.15 1.588L2.35 13.177a2.25 2.25 0 0 0-.1.661V18a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18v-4.162c0-.224-.034-.447-.1-.661L19.24 5.338a2.25 2.25 0 0 0-2.15-1.588H15M2.25 13.5h3.86a2.25 2.25 0 0 1 2.012 1.244l.256.512a2.25 2.25 0 0 0 2.013 1.244h3.218a2.25 2.25 0 0 0 2.013-1.244l.256-.512a2.25 2.25 0 0 1 2.013-1.244h3.859M12 3v8.25m0 0-3-3m3 3 3-3" />
      </svg>
      ${gettext("保存更改")}
    </button>
`}
    <div>
      <label class="tw:input tw:input-neutral tw:h-8">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="tw:size-4">
          <path fill-rule="evenodd" d="M10.5 3.75a6.75 6.75 0 1 0 0 13.5 6.75 6.75 0 0 0 0-13.5ZM2.25 10.5a8.25 8.25 0 1 1 14.59 5.28l4.69 4.69a.75.75 0 1 1-1.06 1.06l-4.69-4.69A8.25 8.25 0 0 1 2.25 10.5Z" clip-rule="evenodd" />
        </svg>
        <input id="search" type="search" class="tw:grow" placeholder="${gettext("搜索...")}" />
      </label>
    </div>
</div>
    `;
    
    fileExplorerElem.prepend(controlsDiv);
}

function createFolder(parentElement: HTMLElement) {
    const folderName = prompt(gettext('请输入文件夹名称') + ':');
    if (!folderName || folderName.trim() === '') return;
    
    const folderDiv = createFolderElem(folderName);
    parentElement.appendChild(folderDiv);
    
    // .folder-header element
    setupFolderEventListeners(folderDiv.firstElementChild as HTMLElement);
    // .folder-content element
    setupSortableForElem(folderDiv.lastElementChild as HTMLElement);

    setHasChanged();
}

function createFileUploader(folderContentElem: HTMLElement) {
    // though we don't allow create multiple file uploaders under the same folder
    // user can make multiple file uploaders under the same folder by drag them
    // into the place (sortable.js)
    if (folderContentElem.querySelector(".file-uploader")) return;
    
    const fileUploaderElem = document.createElement("div");
    fileUploaderElem.className = classNames.fileUploader;
    folderContentElem.append(fileUploaderElem);

    new FileUploader(fileUploaderElem, [], {
        multiple: true,
        disablePreview: true,
    });
    hasChanged = true;
}

/**
 * Deletes a folder
 */
function deleteFolder(folderElement: HTMLElement) {
    if (!confirm(gettext('是否要删除该文件夹'))) {
        return;
    }
    folderElement.parentElement?.remove();
    hasChanged = true;
}

/**
 * Deletes a file
 */
function deleteFile(fileElement: HTMLElement) {
    if (!confirm(gettext('是否要删除该文件'))) {
        return;
    }
    fileElement.remove();
    hasChanged = true;
}


/**
 * Gets path string from an element by traversing up the DOM
 */
function getPathFromElement(element: HTMLElement | null | undefined): string {
    if (!element) return '/';
    
    const path: string[] = [];
    let current = element;
    
    // Traverse up the DOM tree to build the path
    while (current) {
        if (current.classList.contains('folder-content')) {
            const folderHeader = current.previousElementSibling;
            if (folderHeader && folderHeader.classList.contains('folder-header')) {
                const folderName = folderHeader.querySelector('span')?.textContent;
                if (folderName) {
                    path.unshift(folderName);
                }
            }
        }
        
        if (current.id === 'file-explorer') {
            break;
        }
        
        current = current.parentElement as HTMLElement;
    }
    
    return '/' + path.join('/');
}

async function exportJSON() {
    const fileExplorerElem = document.getElementById("file-explorer")! as HTMLDivElement;
    const result: exportFile[] = [];
    
    const fileUploaderElems = fileExplorerElem.querySelectorAll(".file-uploader");
    const fileUploaderStatus = Array.from(fileUploaderElems).map(fileUploaderElem => {
        const fp = FilePond.find(fileUploaderElem);
        return fp.status;
    });
    const allReady = fileUploaderStatus.every(status => status === FilePond.Status.READY);
    if (!allReady) {
        throw new Error(gettext("请等待文件上传结束！"));
    }

    fileUploaderElems.forEach(fileUploaderElem => {
        const fp = FilePond.find(fileUploaderElem);
        const path = getPathFromElement(fileUploaderElem as HTMLElement);
        fp.getFiles().forEach(file => {
            result.push({
                id: file.serverId,
                type: 'upload',
                path
            })
        })
    });


    const fileElems = fileExplorerElem.querySelectorAll(".file");
    fileElems.forEach(fileElem => {
        result.push({
            id: fileElem.getAttribute("data-uuid")!,
            type: 'existing',
            path: getPathFromElement(fileElem as HTMLElement),
        });
    });

    
    return result;
}



function createFolderElem(name: string) {
    const folderDiv = document.createElement('div');
    folderDiv.className = classNames.folder;
            
    // Create folder header
    const folderHeader = document.createElement('div');
    folderHeader.className = classNames.folderHeader;
            
    folderHeader.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="tw:size-6">
  <path fill-rule="evenodd" d="M12.53 16.28a.75.75 0 0 1-1.06 0l-7.5-7.5a.75.75 0 0 1 1.06-1.06L12 14.69l6.97-6.97a.75.75 0 1 1 1.06 1.06l-7.5 7.5Z" clip-rule="evenodd" />
</svg>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="tw:size-6 tw:mx-1">
  <path d="M19.5 21a3 3 0 0 0 3-3v-4.5a3 3 0 0 0-3-3h-15a3 3 0 0 0-3 3V18a3 3 0 0 0 3 3h15ZM1.5 10.146V6a3 3 0 0 1 3-3h5.379a2.25 2.25 0 0 1 1.59.659l2.122 2.121c.14.141.331.22.53.22H19.5a3 3 0 0 1 3 3v1.146A4.483 4.483 0 0 0 19.5 9h-15a4.483 4.483 0 0 0-3 1.146Z" />
</svg>

<span class="tw:font-medium">${name}</span>

<div class="folder-actions tw:ml-2 tw:flex tw:items-center tw:opacity-0 tw:group-hover:opacity-100">
  <div class="tw:cursor-grab tw:text-gray-500 tw:hover:text-blue-500 tw:p-1" title="${gettext("鼠标拽动")}">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tw:size-5"><circle cx="9" cy="12" r="1"/><circle cx="9" cy="5" r="1"/><circle cx="9" cy="19" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="15" cy="5" r="1"/><circle cx="15" cy="19" r="1"/></svg>
  </div>
${canManage ? `
  <button class="add-subfolder-btn tw:cursor-pointer tw:text-gray-500 tw:hover:text-blue-500 tw:p-1" title="${gettext("创建文件夹")}">
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="tw:size-5">
      <path stroke-linecap="round" stroke-linejoin="round" d="M12 10.5v6m3-3H9m4.06-7.19-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" />
    </svg>
  </button>
  <button class="add-file-btn tw:cursor-pointer tw:text-gray-500 tw:hover:text-green-500 tw:p-1" title="${gettext("上传文件")}">
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="tw:size-5">
      <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m3.75 9v6m3-3H9m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" />
    </svg>
  </button>
  <button class="delete-folder-btn tw:cursor-pointer tw:text-gray-500 tw:hover:text-red-500 tw:p-1" title="${gettext("删除文件夹")}">
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="tw:size-5">
      <path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
    </svg>
  </button>` : ''}
</div> `;
            
    folderDiv.appendChild(folderHeader);
            
    // Create container for folder contents
    const folderContent = document.createElement('div');
    folderContent.className = 'folder-content tw:pl-6 tw:ml-5 tw:border-l tw:border-gray-200';
            
    folderDiv.appendChild(folderContent);

    return folderDiv;
}


function renderDirectoryContents(node: DirectoryNode, container: HTMLElement, isRoot: boolean = true) {
    // Sort entries - directories first, then files, both alphabetically
    const sortedEntries = Object.entries(node.children).sort(([nameA, nodeA], [nameB, nodeB]) => {
        if (nodeA.type !== nodeB.type) {
            return nodeA.type === 'directory' ? -1 : 1;
        }
        return nameA.localeCompare(nameB);
    });
    
    for (const [name, childNode] of sortedEntries) {
        if (childNode.type === 'directory') {
            const folderDiv = createFolderElem(name);
                        
            // Recursively render this directory's contents
            renderDirectoryContents(
                childNode,
                folderDiv.lastElementChild as HTMLElement,
                false
            );

            container.appendChild(folderDiv);
        } else if (childNode.type === 'file') {
            renderFile(childNode as FileNode, container);
        }
    }
}

function setupSortableForElem(elem: HTMLElement) {
    new Sortable(elem, {
        group: 'nested',
        swapThreshold: 0.65,
        handle: '.file, .folder, .file-uploader',
        ghostClass: 'tw:bg-gray-100',
        chosenClass: 'tw:bg-gray-300',
        dragClass: 'tw:opacity-80',
            
        onStart: function(evt) {
            const item = evt.item;
            item.classList.add('tw:border', 'tw:border-blue-500', 'tw:shadow-md');
        },
            
        onEnd: function(evt) {
            const item = evt.item;
            item.classList.remove('tw:border', 'tw:border-blue-500', 'tw:shadow-md');

            setHasChanged();
        },
            
        // Prevent dropping files into files and other invalid operations
        onMove: function(evt) {
            const draggedItem = evt.dragged;
            const targetItem = evt.related;
                
            // If trying to drag a folder into a file
            if (draggedItem.classList.contains('subfolder') && 
                targetItem.classList.contains('file')) {
                    return false;
                }
                
            return true;
        }
    });    
}

/**
 * Initialize Sortable.js on all folder content containers
 */
function initializeSortable() {
    const sortableContainerElems = Array.from(document.querySelectorAll('.folder-content'));
    sortableContainerElems.push(document.getElementById('file-explorer')!);
    
    // Apply sortable to all folder content containers
    sortableContainerElems.forEach(elem => {
        setupSortableForElem(elem as HTMLElement);
    });
}

function createChevronDownSvgElem() {
    const chevronDownElem = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    chevronDownElem.setAttribute('viewBox', '0 0 24 24');
    chevronDownElem.setAttribute('fill', 'currentColor');
    chevronDownElem.setAttribute('class', 'tw:size-6');
    chevronDownElem.innerHTML = `
<path fill-rule="evenodd" d="M12.53 16.28a.75.75 0 0 1-1.06 0l-7.5-7.5a.75.75 0 0 1 1.06-1.06L12 14.69l6.97-6.97a.75.75 0 1 1 1.06 1.06l-7.5 7.5Z" clip-rule="evenodd" />`;
    return chevronDownElem;
}

function createChevronRightSvgElem() {
    const chevronDownElem = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    chevronDownElem.setAttribute('viewBox', '0 0 24 24');
    chevronDownElem.setAttribute('fill', 'currentColor');
    chevronDownElem.setAttribute('class', 'tw:size-6');
    chevronDownElem.innerHTML = `
<path fill-rule="evenodd" d="M16.28 11.47a.75.75 0 0 1 0 1.06l-7.5 7.5a.75.75 0 0 1-1.06-1.06L14.69 12 7.72 5.03a.75.75 0 0 1 1.06-1.06l7.5 7.5Z" clip-rule="evenodd" />`;
    return chevronDownElem;
}


function setupFolderEventListeners(folderHeaderElem: HTMLElement) {
    // Remove existing listeners to prevent duplicates
    const newFolderHeaderElem = folderHeaderElem.cloneNode(true) as HTMLElement;
    folderHeaderElem.parentNode?.replaceChild(newFolderHeaderElem, folderHeaderElem);
    
    // Re-add folder toggle listener
    newFolderHeaderElem.addEventListener('click', (e) => {
        // Don't toggle if clicking on action buttons
        if ((e.target as HTMLElement).closest('.folder-actions')) {
            e.stopPropagation();
            return;
        }
        
        e.stopPropagation();
        
        const folderContentElem = newFolderHeaderElem.nextElementSibling as HTMLElement;
        const chevronIconElem = newFolderHeaderElem.firstElementChild as HTMLElement;
        let newChevronIconElem = undefined;
        
        // Toggle folder content visibility
        if (folderContentElem.style.display === 'none') {
            folderContentElem.style.display = 'block';
            newChevronIconElem = createChevronDownSvgElem();
        } else {
            folderContentElem.style.display = 'none';
            newChevronIconElem = createChevronRightSvgElem();
        }
        
        chevronIconElem.replaceWith(newChevronIconElem);
    });
    
    // Add listeners for action buttons if user can manage
    if (canManage) {
        // Add subfolder button listener
        const addSubfolderBtn = newFolderHeaderElem.querySelector('.add-subfolder-btn');
        if (addSubfolderBtn) {
            addSubfolderBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                const folderContentElem = newFolderHeaderElem.nextElementSibling as HTMLElement;
                
                // Ensure folder is open
                if (folderContentElem.style.display === 'none') {
                    folderContentElem.style.display = 'block';
                    
                    // Update chevron
                    const chevronIconElem = newFolderHeaderElem.firstElementChild as HTMLElement;
                    chevronIconElem.replaceWith(createChevronDownSvgElem());
                }
                
                createFolder(folderContentElem);
            });
        }
        
        // Add file button listener
        const addFileBtn = newFolderHeaderElem.querySelector('.add-file-btn');
        if (addFileBtn) {
            addFileBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                const folderContentElem = newFolderHeaderElem.nextElementSibling as HTMLElement;
                
                // Ensure folder is open
                if (folderContentElem.style.display === 'none') {
                    folderContentElem.style.display = 'block';
                    
                    // Update chevron
                    const chevronIconElem = newFolderHeaderElem.firstElementChild as HTMLElement;
                    chevronIconElem.replaceWith(createChevronDownSvgElem());
                }
                
                createFileUploader(folderContentElem);
            });
        }
        
        // Delete folder button listener
        const deleteFolderBtn = newFolderHeaderElem.querySelector('.delete-folder-btn');
        if (deleteFolderBtn) {
            deleteFolderBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                deleteFolder(newFolderHeaderElem);
            });
        }
    }
}

function setupFileEventListeners(fileElem: HTMLElement) {
    // Remove existing listeners to prevent duplicates
    const newFileElem = fileElem.cloneNode(true) as HTMLElement;
    fileElem.parentNode?.replaceChild(newFileElem, fileElem);
    
    newFileElem.addEventListener("click", (e) => {
        if ((e.target as HTMLElement).closest('button')) {
            return;
        }
        
        const link = newFileElem.getAttribute('data-link')!;
        const filename = newFileElem.getAttribute('data-filename')!;
        handleFileAction(link, filename);
    });
    
    if (canManage) {
        const deleteFileBtn = newFileElem.querySelector('.delete-file-btn');
        if (deleteFileBtn) {
            deleteFileBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                deleteFile(newFileElem);
            });
        }
    }
}



/**
 * Update the original setupEventListeners function to use the new specific setup functions
 * and add initialization of Sortable
 */
function setupEventListeners() {
    document.querySelectorAll('.folder-header').forEach(folderElem => {
        setupFolderEventListeners(folderElem as HTMLElement);
    });

    document.querySelectorAll(".file").forEach(fileElem => {
        setupFileEventListeners(fileElem as HTMLElement);
    });
    
    setupSearchEventListeners();
    
    if (canManage) {
        initializeSortable();
    }
}


function renderFile(node: FileNode, container: HTMLElement) {
    const file = node.file;
    const fileIcon = getFileIcon({
        filename: file.filename,
        contentType: file.content_type,
        iconClass: "tw:size-6"
    });
    const fileDiv = document.createElement('div');
    fileDiv.className = classNames.file;
    
    fileDiv.classList.add("tw:cursor-pointer");
    fileDiv.setAttribute("data-link", file.link);
    fileDiv.setAttribute("data-filename", file.filename);
    fileDiv.setAttribute("data-uuid", file.uuid);
    fileDiv.setAttribute("role", "button");
    fileDiv.innerHTML = `
${fileIcon}
<span>${file.filename}</span>
${canManage ? `
<div class="file-actions tw:flex tw:items-center tw:opacity-0 tw:group-hover:opacity-100">
  <div class="tw:cursor-grab tw:text-gray-500 tw:hover:text-blue-500 tw:p-1" title="${gettext("鼠标拽动")}">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tw:size-5"><circle cx="9" cy="12" r="1"/><circle cx="9" cy="5" r="1"/><circle cx="9" cy="19" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="15" cy="5" r="1"/><circle cx="15" cy="19" r="1"/></svg>
  </div>
  <button class="delete-file-btn tw:cursor-pointer tw:text-gray-500 tw:hover:text-red-500 tw:p-1" title="${gettext("删除文件")}">
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="tw:size-5">
      <path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
    </svg>
  </button>
</div>` : ''}
<div class="tw:ml-auto tw:opacity-0 tw:group-hover:opacity-100 tw:transition-opacity">
  <span>${filesize(file.file_size)}</span>
  <span>${file.content_type}</span>
  <span>${formatDateZhCn(file.uploaded_at)}</span>
</div>`;
    
    container.appendChild(fileDiv);
}




/**
 * Sets up event listeners for the file search functionality.
 * This function initializes the search box, clear button, and file filtering logic.
 */
function setupSearchEventListeners(): void {
    // Search functionality elements
    const searchInput = document.getElementById('search') as HTMLInputElement | null;
    const clearSearchButton = document.getElementById('clear-search') as HTMLElement | null;
    const searchResults = document.getElementById('search-results') as HTMLElement | null;
    const resultCount = document.getElementById('result-count') as HTMLElement | null;
    const noResults = document.getElementById('no-results') as HTMLElement | null;
    
    // Early return if any required elements are missing
    if (!searchInput || !clearSearchButton || !searchResults || !resultCount || !noResults) {
        console.warn('Search functionality elements not found, skipping search setup');
        return;
    }
    
    /**
     * Handles the search input event.
     * @param searchTerm - The search term to filter files by
     */
    const handleSearch = (searchTerm: string): void => {
        const files = document.querySelectorAll('.file') as NodeListOf<HTMLElement>;
        
        if (searchTerm === '') {
            // Reset search state
            searchResults.classList.add('tw:hidden');
            
            // Show all files and reset folder display
            files.forEach(file => {
                file.classList.remove('tw:bg-yellow-100');
                file.style.display = '';
            });
            
            // Reset all folders to default state
            document.querySelectorAll('.folder-content').forEach(content => {
                (content as HTMLElement).style.display = '';
            });
            
            return;
        }
        
        // Hide all files initially
        files.forEach(file => {
            file.style.display = 'none';
            file.classList.remove('tw:bg-yellow-100');
        });
        
        // Keep track of matched files
        let matchCount = 0;
        
        // Filter files based on search term
        files.forEach(file => {
            const fileNameElem = file.querySelector('span');
            const fileName = fileNameElem?.textContent?.toLowerCase() || '';
            
            if (fileName.includes(searchTerm.toLowerCase())) {
                // Show matching file
                file.style.display = 'flex';
                file.classList.add('tw:bg-yellow-100'); // Highlight matched files
                matchCount++;
                
                // Ensure all parent folders are open
                ensureParentFoldersOpen(file);
            }
        });
        
        // Update search results display
        searchResults.classList.remove('tw:hidden');
        resultCount.textContent = matchCount.toString();
        
        if (matchCount === 0) {
            noResults.classList.remove('tw:hidden');
        } else {
            noResults.classList.add('tw:hidden');
        }
    };
    
    /**
     * Ensures all parent folders are expanded for visible files.
     * @param fileElement - The file element whose parent folders need to be opened
     */
    const ensureParentFoldersOpen = (fileElement: HTMLElement): void => {
        let current = fileElement.parentElement;
        
        while (current) {
            // If this is a folder content element, ensure it's visible
            if (current.classList.contains('folder-content')) {
                current.style.display = 'block';
                
                // Get the folder header element (previous sibling of folder-content)
                const folderHeader = current.previousElementSibling;
                
                if (folderHeader && folderHeader.classList.contains('folder-header')) {
                    const chevronIcon = folderHeader.firstElementChild;
                    
                    if (chevronIcon) {
                        chevronIcon.replaceWith(createChevronDownSvgElem());
                    }
                }
            }
            
            // Move up to the next parent
            current = current.parentElement;
        }
    };
    
    // Add event listeners
    searchInput.addEventListener('input', function() {
        const searchTerm = this.value.trim();
        handleSearch(searchTerm);
    });
    
    clearSearchButton.addEventListener('click', function() {
        searchInput.value = '';
        handleSearch('');
    });
}



(function () {
    ready(async () => {
        const publicFilesReq = await get(getApiPath());
        let publicFiles = await publicFilesReq.json();

        try {
            const perm = await getCurrentUserPerm();
            canManage = perm.is_superuser || perm.perm_can_manage_resources;
        } catch {
            canManage = false;
        }

        publicFiles = v.parse(v.array(File), publicFiles);
        setupFileExplorer(publicFiles);

        window.onbeforeunload = function() {
            if (hasChanged) {
                return gettext("您的修改还没保存！");
            }
            return undefined;
        }
    });
})();

